import { _decorator, Node, UITransform, Layout, LabelComponent, NodeEventType, Label } from 'cc';
import * as ccenv from 'cc/env'
import { GameManager } from '../manager/GameManager';
import { PokerIntensify } from '../data/PokerIntensify';
import { PokerConfig } from '../config/PokerConfig';
import { notNull } from '../../libs/utils/ExtUtils';
import ValueWatcher from '../../libs/watch/ValueWatcher';
import PokerItem from '../data/PokerItem';
import SnapFloor from '../../libs/phaser/math/snap/SnapFloor.js';
const { ccclass, property } = _decorator;


const isPC = ccenv.MAC || ccenv.WINDOWS || ccenv.LINUX;
const EventClick = isPC ? NodeEventType.MOUSE_DOWN : NodeEventType.TOUCH_START;

@ccclass('PokerHintDialog')
export class PokerHintDialog {

    @property({ type: Node })
    root: Node = null!;

    @property({ type: Node })
    title: Node = null!;

    @property({ type: Node })
    origin: Node = null!;

    @property({ type: Node })
    hint: Node = null!;

    @property({ type: Node })
    cancel: Node = null!;

    @property({ type: Node })
    sure: Node = null!;

    @property({ type: Node })
    close: Node = null!;



    //#region Hint Dialog
    /**
     * 根据给定的牌进行显示提示牌
     * 
     * @param origin 
     * @param picker 
     * @returns 是否存在提示牌
     */
    async pokerHintDialog(
        game: GameManager,
        origin: PokerIntensify[],
        picker: ((target: PokerIntensify[]) => void),
    ) {
        const poker_item_joker = origin.filter(v => PokerConfig.pokerIsJoker(v.poker));
        if (poker_item_joker.length === 0) {
            return false;
        }
        if (poker_item_joker.length === 1) {
            return this.pokerHintSingleDialog(game, origin, poker_item_joker[0], picker);
        } else {
            return this.pokerHintMultipleDialog(game, origin, poker_item_joker, picker);
        }
    }

    //#region Hint Single
    async pokerHintSingleDialog(game: GameManager, origin: PokerIntensify[], joker: PokerIntensify, picker: ((target: PokerIntensify[]) => void)) {

        const poker_origin = origin.map(v => v.poker);
        const poker_other = PokerConfig.pokerJokerFilter(poker_origin);
        if (poker_other.length === 0) {
            console.log('pokerHintSingleDialog', '其他卡牌,非鬼牌,数量=0');
            return false;
        }

        const poker_hint = PokerConfig.pokerHint(poker_other).reduce<PokerIntensify[]>((pre, value) => {
            pre.push(...value.map(v => game.deck.getPokerIntensify(v)))
            return pre;
        }, []);

        if (poker_hint.length === 0) {
            console.log('pokerHintSingleDialog', '无推荐卡牌');
            return false;
        }

        notNull(this.title.getComponent(LabelComponent), (comp) => {
            comp.string = '单小丑牌提示'
        });

        const dialogHide = () => {
            // 解注册监听
            this.close.off(EventClick);
            this.cancel.off(EventClick);
            this.sure.off(EventClick);

            // 回收
            while (this.origin.children.length > 0) {
                game.poolPokerRecycle(this.origin.children[0]);
            }
            while (this.hint.children.length > 0) {
                game.poolPokerRecycle(this.hint.children[0]);
            }

            // 设置不可见
            this.root.active = false;
        }

        const watchSelect: ValueWatcher<PokerItem | null> = new ValueWatcher(null);

        // 设置目标牌组
        const origin_poker_item: PokerItem[] = []
        for (const element of poker_origin) {
            const item = await game.poolPokerReuse(element);
            this.origin.addChild(item.pokerNode);
            origin_poker_item.push(item);
        }

        // 设置提示牌组
        const hint_poker_item: PokerItem[] = []
        for (const element of poker_hint) {
            const item = await game.poolPokerReuse(element);
            this.hint.addChild(item.pokerNode);
            hint_poker_item.push(item);
            // 添加监听事件
            const click = (...props: any[]) => {
                // 进行选中
                if (item === watchSelect.value) {
                    watchSelect.reset()
                } else {
                    watchSelect.change(item)
                }
            }
            item.pokerNode.on(EventClick, click, this);
            item.pokerNode.once('onRecycle', () => {
                console.log(' poker onRecycle ')
                item.pokerNode.off(EventClick, click, this);
            })
        }

        watchSelect.listenerChange((watch, curr, pre) => {
            for (const element of hint_poker_item) {
                element.changeSelect(element === curr);
            }
        })

        this.updateLayout(this.hint);


        // 添加点击事件
        this.close.once(EventClick, () => {
            dialogHide();
        })

        notNull(this.cancel.getComponentInChildren(LabelComponent), (comp) => {
            comp.string = '取消'
            this.cancel.once(EventClick, () => {
                dialogHide();
            })
        });
        notNull(this.sure.getComponentInChildren(LabelComponent), (comp) => {
            comp.string = "确定"
            this.sure.once(EventClick, () => {
                if (watchSelect.value !== null) {
                    dialogHide();
                    // 更新process;
                    picker([...origin.filter(v => v !== joker), watchSelect.value.pokerIntensify])
                }
            })
        });


        this.root.active = true;

        return true;
    }


    //#region Hint Multiple
    async pokerHintMultipleDialog(game: GameManager, origin: PokerIntensify[], joker: PokerIntensify[],
        picker: ((target: PokerIntensify[]) => void)) {

        const process_poker_recorder: PokerIntensify[][] = [];
        let process_poker: PokerIntensify[] = [...origin];

        notNull(this.title.getComponent(LabelComponent), (comp) => {
            comp.string = '小丑牌提示'
        });

        // 回收
        const pokerRecycle = () => {
            while (this.origin.children.length > 0) {
                game.poolPokerRecycle(this.origin.children[0]);
            }
            while (this.hint.children.length > 0) {
                game.poolPokerRecycle(this.hint.children[0]);
            }
        }

        const dialogHide = () => {
            // 清空
            pokerRecycle();

            // 解注册监听
            this.close.off(EventClick);
            this.cancel.off(EventClick);
            this.sure.off(EventClick);

            // 设置不可见
            this.root.active = false;
        }

        // 添加 关闭 点击事件
        this.close.once(EventClick, () => {
            dialogHide();
        })

        const updateBt = () => {
            console.log('updateBt 1');
            if (process_poker_recorder.length === 0) {

                console.log('updateBt 2');
                notNull(this.cancel.getComponentInChildren(Label), (comp) => {
                    comp.string = '取消'
                });
                notNull(this.sure.getComponentInChildren(Label), (comp) => {
                    comp.string = "下一步"
                });
            } else if (process_poker_recorder.length === joker.length) {

                console.log('updateBt 3');
                notNull(this.cancel.getComponentInChildren(Label), (comp) => {
                    comp.string = '上一步'
                });
                notNull(this.sure.getComponentInChildren(Label), (comp) => {
                    comp.string = "确定"
                });
            } else {
                console.log('updateBt 4');
                notNull(this.cancel.getComponentInChildren(Label), (comp) => {
                    comp.string = '上一步'
                });
                notNull(this.sure.getComponentInChildren(Label), (comp) => {
                    comp.string = "下一步"
                });
            }
        }

        const watchSelect: ValueWatcher<PokerItem | null> = new ValueWatcher(null);

        const showStep = async (curr: PokerIntensify[]): Promise<boolean> => {
            const poker_other_enum = curr.filter(v => !PokerConfig.pokerIsJoker(v.poker)).map(v => v.poker);
            if (poker_other_enum.length === 0) {
                console.log('pokerHintSingleDialog', '其他卡牌,非鬼牌,数量=0');
                return false;
            }
            const poker_hint_intensify = PokerConfig.pokerHint(poker_other_enum).reduce<PokerIntensify[]>((pre, value) => {
                pre.push(...value.map(v => game.deck.getPokerIntensify(v)))
                return pre;
            }, []);

            if (poker_hint_intensify.length === 0) {
                console.log('pokerHintSingleDialog', '无推荐卡牌');
                return false;
            }

            // 初始化操作
            pokerRecycle();
            watchSelect.removeAllListeners();
            watchSelect.reset();

            // 设置目标牌组
            const origin_poker_item: PokerItem[] = []
            for (const element of curr) {
                const item = await game.poolPokerReuse(element);
                this.origin.addChild(item.pokerNode);
                origin_poker_item.push(item);
            }

            // 设置提示牌组
            const hint_poker_item: PokerItem[] = []
            for (const element of poker_hint_intensify) {
                const item = await game.poolPokerReuse(element);
                this.hint.addChild(item.pokerNode);
                hint_poker_item.push(item);
                // 添加监听事件
                const click = (...props: any[]) => {
                    // 进行选中
                    if (item === watchSelect.value) {
                        watchSelect.reset()
                    } else {
                        watchSelect.change(item)
                    }
                }
                item.pokerNode.on(EventClick, click, this);
                item.pokerNode.once('onRecycle', () => {
                    console.log(' poker onRecycle ')
                    item.pokerNode.off(EventClick, click, this);
                })
            }


            this.updateLayout(this.hint);



            // 更新监听
            watchSelect.listenerChange((watch, curr, pre) => {
                for (const element of hint_poker_item) {
                    element.changeSelect(element === curr);
                }
            })

            //更新按钮
            updateBt();

            // 显示弹窗
            this.root.active = true;

            // 设置数据
            process_poker = curr;

            return true;
        }

        this.cancel.on(EventClick, () => {
            if (process_poker_recorder.length === 0) {
                // '取消'
                dialogHide();
            } else if (process_poker_recorder.length === joker.length) {
                // '上一步'
                process_poker = process_poker_recorder.pop() || [...origin];
                showStep(process_poker);
            } else {
                // '上一步'
                process_poker = process_poker_recorder.pop() || [...origin];
                showStep(process_poker);
            }
        })
        this.sure.on(EventClick, () => {
            const select = watchSelect.value
            if (process_poker_recorder.length === 0) {
                // "下一步"
                if (select) {
                    const currJoker = joker[process_poker_recorder.length];
                    const process = process_poker.map(v => v.poker === currJoker.poker ? select.pokerIntensify : v);
                    process_poker_recorder.push([...process_poker]);
                    showStep(process);
                }
            } else if (process_poker_recorder.length === joker.length - 1) {
                // "确定"
                if (select) {
                    const currJoker = joker[process_poker_recorder.length];
                    const process = process_poker.map(v => v.poker === currJoker.poker ? select.pokerIntensify : v);
                    const process_joker = process.filter(v => PokerConfig.pokerIsJoker(v.poker));
                    if (process_joker.length > 0) {
                        throw ` 存在异常 , 还存在小丑牌, ${process.map(v => v.poker).join('-')} , currJoker=${currJoker} `;
                    }
                    dialogHide();
                    picker(process);
                }
            } else {
                // "下一步"
                if (select) {
                    const currJoker = joker[process_poker_recorder.length];
                    const process = process_poker.map(v => v === currJoker ? select.pokerIntensify : v);
                    process_poker_recorder.push([...process_poker]);
                    showStep(process);
                }
            }
        })
        return showStep(process_poker);
    }


    updateLayout(node: Node) {
        const childSize = node.children.length;
        if (childSize <= 0) return;
        const parent = node.parent;
        if (!parent) return;
        const transform = node.children[0].getComponent(UITransform);
        if (!transform) return;
        const childWidth = transform.width;
        const pokerLayout = node.getComponent(Layout);
        if (!pokerLayout) return;
        const pokerTransform = node.getComponent(UITransform);
        if (!pokerTransform) return;
        const pokerParentTransform = parent.getComponent(UITransform);
        if (!pokerParentTransform) return;

        pokerParentTransform.scheduleOnce(() => {

            const widthPokers = childSize * childWidth;
            const widthParent = pokerParentTransform.width;

            if (widthPokers >= SnapFloor(widthParent, childWidth)) {
                pokerLayout.resizeMode = Layout.ResizeMode.NONE;
                pokerTransform.width = widthParent;
            } else {
                pokerLayout.resizeMode = Layout.ResizeMode.CONTAINER;
            }

            if (pokerLayout.resizeMode === Layout.ResizeMode.NONE) {
                pokerLayout.spacingX = (SnapFloor((widthParent - childWidth) / (childSize - 1), 0.5)) - childWidth;
            }
        })
    }
}
